/*oOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO

Authors: Nitay Megides
		 Rachel Banino

Project: Exercise 1

Using:	Hw1InputManager.h
		Hw1OutputManager.h
		Hw1TextFileReader.h
		Hw1Types.h
		ProductList.h
		UserList.h
		InventoryList.h
		Logger.h

Description:
The main module of this project. Contains the main() function - The entry 
point of this application. 
oOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoOoO*/

#include "Hw1InputManager.h"
#include "Hw1OutputManager.h"
#include "Hw1TextFileReader.h"
#include "Hw1Types.h"

#include "ProductList.h"
#include "UserList.h"
#include "InventoryList.h"
#include "Logger.h"

#include <assert.h>
#include <stdio.h>


TMoney Money;


BOOL BuyFromSupplier(TProductID productID, TUserID customerID, TMoney price)
{
	PProduct product = GetProduct(productID);
	PUser user = GetUser(customerID);

    AssertUser(user);
    AssertProduct(product);

	// Check all valid
	if ((product != NULL) && (user != NULL))
	{
		// If we have enough money
		if (Money >= price)
		{
			// Buy it!
			LogBuyFromSupplier(product->Name, user->Name, price);
			Money -= price;
			AddInventoryProduct(productID, price);

			return TRUE;
		}
		else
		{
			// Not enough money... fail
			LogBuyFromSupplierFailure(product->Name, user->Name, price);

			return FALSE;
		}
	}

	return FALSE;
}

BOOL SellToCustomer(TProductID productID, TUserID customerID, TMoney price)
{
	PProduct product = GetProduct(productID);
	PUser user = GetUser(customerID);
	PInventoryProduct inventoryItem;

    AssertUser(user);
    AssertProduct(product);

	if ((product != NULL) && (user != NULL))
	{
		// If we have it in stock
		inventoryItem = GetInventoryProduct(productID, price);
		if (inventoryItem != NULL)
		{
			LogSellToCustomer(product->Name, user->Name, price);
			Money += price;
			RemoveInventoryProduct(productID, inventoryItem->Price);

			return TRUE;
		}
		else
		{
			LogSellToCustomerFailure(product->Name, user->Name, price);

			return FALSE;
		}
	}

	return FALSE;
}

void AddInventoryFromFile(char* filename)
{
	OutputMgr_ReportInventory(AXN_RECEIVED_INVENTORY);

	LoadInventoryList(filename);
}

void CreateInventoryFile(char* filename)
{
	OutputMgr_ReportInventory(AXN_SAVED_INVENTORY_DATA_TO_FILE);

	LogCreateInventoryFile();

    SaveInventoryList(filename);
}

int main(int argc, char* argv[])
{
	int i;

	char* productsFilename = argv[2];
	char* usersFilename = argv[3];
	char* logFilename = argv[4];
	
	TextFileReader reader;

	TRequest currentRequest;

	if (argc < 7)
		return -1;

	Money = String2TMoney(argv[1]);

    // First initialize the logger
	LoggerInitialize(logFilename);

    // Initialize everything
	InitializeProductList();
	InitializeInventoryList();
	InitializeUserList();


	// Read products
	reader = CreateTextFileReader(productsFilename);
	assert(reader.IsInitialized);
	for (i = 0; i < reader.NumOfLines; i++)
	{
		if ((reader.WordsArr[i][0] != NULL) && (reader.WordsArr[i][1] != NULL))
		{
			AddProduct(String2TProductID(reader.WordsArr[i][1]), reader.WordsArr[i][0]);
		}	
	}
	DeleteTextFileReader(reader);

	// Read users
	reader = CreateTextFileReader(usersFilename);
	assert(reader.IsInitialized);
	for (i = 0; i < reader.NumOfLines; i++)
	{
		if ((reader.WordsArr[i][0] != NULL) && 
			(reader.WordsArr[i][1] != NULL) &&
			(reader.WordsArr[i][2] != NULL))
		{
			AddUser(
				String2TUserID(reader.WordsArr[i][2]),
				reader.WordsArr[i][0], 
				reader.WordsArr[i][1]);
		}		
	}
	DeleteTextFileReader(reader);

	// Initialize input and output manager (No need to assert here - Both modules check input)
	OutputMgr_Initialize(argv[6]);
	InptMgr_Initialize(argv[5]);


	// The main loop on the InputMngr GetNext and do stuff
	currentRequest = InptMgr_GetNextRequest();
	while (currentRequest.Operation != IM_END_OF_INPUT)
	{
		switch (currentRequest.Operation)
		{
		case IM_SELL_TO_CUSTOMER :
			if (SellToCustomer(
				currentRequest.TransactionData.ProductID, 
				currentRequest.TransactionData.UserID, 
				currentRequest.TransactionData.Cost))
			{
				OutputMgr_ReportTransaction(AXN_ACCEPTED, currentRequest.TransactionData);
			}
			else
			{
				OutputMgr_ReportTransaction(AXN_REFUSED, currentRequest.TransactionData);
			}

			break;
		case IM_BUY_FROM_SUPPLIER :
			if (BuyFromSupplier(
				currentRequest.TransactionData.ProductID,
				currentRequest.TransactionData.UserID,
				currentRequest.TransactionData.Cost))
			{
				OutputMgr_ReportTransaction(AXN_ACCEPTED, currentRequest.TransactionData);
			}
			else
			{
				OutputMgr_ReportTransaction(AXN_REFUSED, currentRequest.TransactionData);
			}
			break;
		case IM_CREATE_INVENTORY_FILE :
			CreateInventoryFile(currentRequest.Filename);
			break;
		case IM_ADD_INVENTORY_FROM_FILE :
			AddInventoryFromFile(currentRequest.Filename);
			break;
		case IM_END_OF_INPUT:
			// We shouldn't get here! It is checked in the while clause
			printf("Control FLow Error!");
			assert(FALSE);
			break;
		case NUM_OF_INPUT_OPERATIONS:
		case IM_NO_OPERATION:
		default:
			// Nothing to see here. Move along...		
			break;
		}

		currentRequest = InptMgr_GetNextRequest();
	}

	//PrintInventoryList();	
	
	// Clean up everything
	FreeInventoryList();
	FreeProductList();
	FreeUserList();

	OutputMgr_Cleanup();
	InptMgr_CleanUp();
	LoggerCleanup();

	return 0;
}

